package com.jack.concurrency;

/**
 * Created by zhang_j on 2019/11/29
 * synchronized一直是元老级角色，在多线程并发编程中可以使用它来解决线程安全问题中提到的原子性，可见性以及顺序性。
 *      JDK1.6中为了减少获得锁和释放锁带来的性能消耗而引入的偏向锁和轻量级锁，以及锁的存储结构和升级过程
 *
 * synchronized有三种使用方式：方法锁，对象锁，类锁。其中在方法锁层面又分为：
 *      修饰实例方法，作用于当前实例加锁，进入同步代码前要获得当前实例的锁
 *      静态方法，作用于当前类对象加锁，进入同步代码前要获得当前对象的锁
 *      修饰代码块，指定加锁对象，对给定对象加锁，进入同步代码库前要获得给定对象的锁
 * synchronized (MySynchronized.class){}  //类锁
 * synchronized (mySynchronized){}  //对象锁
 *
 * synchronized锁的原理（三个问题）：
 *      synchronized是如何实现锁的
 *      为什么任何一个对象都可以成为锁
 *      锁存在哪个地方
 */
public class MySynchronized {
    /**
        多线程环境下，方法内的变量是线程安全的。
        多个线程同时处理一个实例，这个实例内的变量是不安全的。
        多个线程注入同一个类的不同实例，实例中的变量是安全的。
        Synchronized获取到的锁是对象锁，当多个线程访问同一个对象时，哪个线程先执行带Synchronized关键字的方法，那个线程就持有该方法所属对象的锁，其他线程是等待状态
        调用关键字Synchronized声明的方法一定是排队运行的，另外，只有共享资源的访问才需要同步化
        一个对象内有多个Synchronized方法/块时
            A线程先持有object对象的锁，B线程可以以异步的方式调用object对象的非Synchronized方法
            A线程先持有object对象的锁，B线程如果此时调用object对象中的任一Synchronized方法，则需要等待A线程释放锁，也就是同步
        Synchronized不能继承，举个例子，父类方法被Synchronized修饰，子类重写父类的该方法，但并不带Synchronized修饰，就不会产生同步的效果

     */
    int a = 0;
    int b = 0;

    public static void main(String[] args) {
        MySynchronized mySynchronized = new MySynchronized();
        /**
         *  实例中有两个变量，有一个Synchronized声明的方法，方法执行过程中，若一个变量赋值完成，另一个变量未赋值完成，
         *      此时调用实例中非Synchronized方法去获取实例中两个变量的值，此时就会出现脏读，解决的办法是读取的方法上也加入Synchronized声明
         */
        new Thread(()->mySynchronized.synFunc()).start();
        mySynchronized.read();

//        for(int i=0;i<3;i++){
//            new Thread(()->mySynchronized.synFunc()).start();
//        }
//        for(int i=0;i<3;i++){
//            new Thread(()->mySynchronized.synFunc()).start();
//        }

//        for(int i=0;i<3;i++){
//            new Thread(()->mySynchronized.nonsynFunc()).start();
//        }
//        for(int i=0;i<3;i++){
//            new Thread(()->mySynchronized.nonsynFunc()).start();
//        }
    }
    public synchronized void synFunc(){
        a++;
        System.out.println("a:"+a);
    }

    public void nonsynFunc(){
        b++;
        System.out.println("b:"+b);
    }

    public void read(){
        System.out.println("a:"+a);
        System.out.println("b:"+b);
    }
}
